package com.smedi.ismedi.organization.core.application.query.impl;

import com.smedi.ismedi.authority.starter.response.AuthorityAccessResponse;
import com.smedi.ismedi.authority.starter.util.AuthorityUtil;
import com.smedi.ismedi.organization.core.application.command.OrganizationListQueryCommand;
import com.smedi.ismedi.organization.core.application.command.OrganizationOneQueryCommand;
import com.smedi.ismedi.organization.core.application.convert.AppConverter;
import com.smedi.ismedi.organization.core.application.query.HrOrganizationQueryService;
import com.smedi.ismedi.organization.core.application.query.vo.AllOrganizationVo;
import com.smedi.ismedi.organization.core.application.query.vo.HrOrganizationVo;
import com.smedi.ismedi.organization.core.domain.aggregatemodel.HrOrganization;
import com.smedi.ismedi.organization.core.domain.aggregatemodel.dto.OrganizationQuery;
import com.smedi.ismedi.organization.core.domain.aggregatemodel.model.DingOrg;
import com.smedi.ismedi.organization.core.domain.aggregatemodel.model.Organization;
import com.smedi.ismedi.organization.core.domain.repository.HrOrganizationRepository;
import com.smedi.ismedi.organization.core.domain.service.HrOrganizationDomainService;
import com.smedi.ismedi.organization.core.infrastructure.constant.CustomError;
import com.smedi.ismedi.organization.core.infrastructure.enumerate.HrOrganizationTypeEnum;
import com.smedi.ismedi.web.starter.exception.LogicException;
import com.smedi.ismedi.web.starter.util.DozerUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@AllArgsConstructor
public class HrOrganizationQueryServiceImpl implements HrOrganizationQueryService {
    private final HrOrganizationRepository hrOrganizationRepository;
    private final HrOrganizationDomainService hrOrganizationDomainService;

    private final DozerUtil dozerUtil;

    private final AppConverter appConverter;
    private final AuthorityUtil authorityUtil;

    /**
     * 行政组织类型转换
     *
     * @param modal
     * @return
     */
    private HrOrganizationVo hrOrganizationToVo(HrOrganization modal) {
        HrOrganizationVo vo = dozerUtil.convertor(modal, HrOrganizationVo.class);
        vo.setTypeMeaning(HrOrganizationTypeEnum.getName(modal.getType())); // 组织类型
        // 子组织
        vo.setHrOrganizationChildren(dozerUtil.convertor(hrOrganizationDomainService.getHrOrganizationChildrenByTree(modal.getHrOrganizationId()), HrOrganizationVo.class));
        return vo;
    }

    /**
     * 特定组织类型下的行政组织类型转换
     *
     * @param modal
     * @param typeList
     * @return
     */
    private HrOrganizationVo hrOrganizationToVoWithTypeList(HrOrganization modal, List<String> typeList) {
        HrOrganizationVo vo = dozerUtil.convertor(modal, HrOrganizationVo.class);
        vo.setTypeMeaning(HrOrganizationTypeEnum.getName(modal.getType())); // 组织类型
        // 子组织
        vo.setHrOrganizationChildren(dozerUtil.convertor(hrOrganizationDomainService.getHrOrganizationChildrenByTreeWithTypeList(modal.getHrOrganizationId(), typeList), HrOrganizationVo.class));
        return vo;
    }

    @Override
    public HrOrganizationVo getHrOrganizationViewRoot() {
        HrOrganization root = hrOrganizationRepository.selectHrOrganizationRoot();
        return dozerUtil.convertor(root, HrOrganizationVo.class);
    }

    @Override
    public List<HrOrganization> getByHrOrganizationIds(List<Long> organizationIds) {
        return hrOrganizationRepository.selectByHrOrganizationIds(organizationIds);
    }

    @Override
    public List<HrOrganizationVo> getAllHrOrganizationList() {
        List<HrOrganization> hrOrganizations = hrOrganizationRepository.queryAllSkipSql();

        return dozerUtil.convertor(hrOrganizations, HrOrganizationVo.class);
    }

    @Override
    public List<HrOrganizationVo> getHrOrganizationTree(Long hrOrganizationId) {
        List<HrOrganizationVo> list = new ArrayList<>();
        // 判断当前组织id是否为空，如果为空，则抓取当前有权限查看的所有根节点组织
        if (hrOrganizationId == null) {
            List<HrOrganization> modals = hrOrganizationRepository.selectAllRoots();
            for (HrOrganization modal : modals) {
                list.add(hrOrganizationToVo(modal));
            }
        } else {
            // 获取当前组织
            HrOrganization modal = hrOrganizationRepository.selectByHrOrganizationId(hrOrganizationId);
            if (modal != null) {
                list.add(hrOrganizationToVo(modal));
            }
        }
        return list;
    }

    @Override
    public HrOrganizationVo getHrOrganizationView(Long hrOrganizationId) {
        HrOrganization hrOrganization = hrOrganizationRepository.selectByHrOrganizationId(hrOrganizationId);
        if (hrOrganization != null) {
            return hrOrganizationToVo(hrOrganization);
        } else {
            throw LogicException.raise(CustomError.HR_ORGANIZATION_NOT_EXIST);
        }
    }

    @Override
    public HrOrganizationVo getHrOrganizationViewWithTypeList(Long hrOrganizationId, List<String> typeList) {
        HrOrganization hrOrganization = hrOrganizationRepository.selectByHrOrganizationId(hrOrganizationId);
        if (hrOrganization != null) {
            return hrOrganizationToVoWithTypeList(hrOrganization, typeList);
        } else {
            throw LogicException.raise(CustomError.HR_ORGANIZATION_NOT_EXIST);
        }
    }

    @Override
    public List<Long> getHrOrganizationChildrenIdList(Long hrOrganizationId) {
        List<HrOrganization> list = hrOrganizationDomainService.getHrOrganizationChildrenByList(hrOrganizationId);
        List<Long> arrayList = new ArrayList<>();
        for (HrOrganization hrOrganization : list) {
            arrayList.add(hrOrganization.getHrOrganizationId());
        }
        if (!arrayList.contains(hrOrganizationId)) {
            arrayList.add(0, hrOrganizationId);
        }
        return arrayList;
    }

    @Override
    public Map<Long, String> getHrOrganizationChildrenMap(Long hrOrganizationId) {
        List<HrOrganization> list = hrOrganizationDomainService.getHrOrganizationChildrenByList(hrOrganizationId);
        HrOrganization basic = hrOrganizationRepository.selectByHrOrganizationId(hrOrganizationId);
        Map<Long, String> maps = new HashMap<>();
        if (basic != null) {
            maps.put(basic.getHrOrganizationId(), basic.getFullName());
        } else {
            return new HashMap<>();
        }

        for (HrOrganization hrOrganization : list) {
            if (!maps.containsKey(hrOrganization.getHrOrganizationId())) {
                maps.put(hrOrganization.getHrOrganizationId(), hrOrganization.getFullName());
            }
        }

        return maps;
    }

    @Override
    public List<HrOrganizationVo> getHrOrganizationByHrOrganizationIds(List<Long> hrOrganizationIds) {
        List<HrOrganizationVo> hrOrganizationVos = new ArrayList<>();
        for (Long hrOrganizationId : hrOrganizationIds) {
            HrOrganization hrOrganization = hrOrganizationRepository.selectByHrOrganizationId(hrOrganizationId);
            HrOrganizationVo hrOrganizationVo = dozerUtil.convertor(hrOrganization, HrOrganizationVo.class);
            if (hrOrganizationVo != null) {
                hrOrganizationVos.add(hrOrganizationVo);
            }
        }
        return hrOrganizationVos;
    }

    /**
     * 领域转换成视图
     *
     * @param list
     * @return
     */
    private List<HrOrganizationVo> domainTransformToView(List<HrOrganization> list) {
        List<HrOrganizationVo> views = dozerUtil.convertor(list, HrOrganizationVo.class);

        views.stream().forEach(view -> {
            if (view.getParentId() != null) {
                HrOrganizationVo parent = getHrOrganizationView(view.getParentId());
                view.setParentFullName(parent.getFullName());
                view.setParentShortName(parent.getShortName());
            }
        });

        return views;
    }

    @Override
    public List<HrOrganizationVo> queryHrOrganizationListByFullName(String fullName) {
        List<HrOrganization> list = hrOrganizationRepository.selectByFullNameLike(fullName);
        return domainTransformToView(list);
    }

    @Override
    public List<HrOrganizationVo> queryHrOrganizationListByFullNameList(List<String> fullNameList) {
        List<HrOrganization> list = hrOrganizationRepository.selectByFullNameList(fullNameList);
        return dozerUtil.convertor(list,HrOrganizationVo.class);
    }

    @Override
    public List<HrOrganizationVo> queryAllProjectManagementHROrganizationList() {
        List<String> typeList = new ArrayList<>();

        typeList.add(HrOrganizationTypeEnum.PROJECT_MANAGEMENT_ORGANIZATION.getValue());

        return domainTransformToView(hrOrganizationRepository.selectHrOrganizationByTypeList(typeList));
    }

    @Override
    public List<HrOrganizationVo> queryAllProjectManagementHROrganizationListNew() {
        List<String> typeList = new ArrayList<>();

        typeList.add(HrOrganizationTypeEnum.PROJECT_MANAGEMENT_ORGANIZATION.getValue());
        List<HrOrganization> hrOrganizations=hrOrganizationRepository.getAllHrOrganization();

        return dozerUtil.convertor(hrOrganizationRepository.selectHrOrganizationByTypeListNew(typeList,hrOrganizations),HrOrganizationVo.class);
    }

    /**
     * 循环获取符合类型要求的上级组织
     *
     * @param hrOrganizationVo
     * @param type
     * @return
     */
    private HrOrganizationVo findParentByType(HrOrganizationVo hrOrganizationVo, String type) {
        if (type.equals(hrOrganizationVo.getType())) {
            return hrOrganizationVo;
        } else {
            if (hrOrganizationVo.getParentId() == null) {
                return null;
            } else {
                try {
                    HrOrganizationVo parent = getHrOrganizationView(hrOrganizationVo.getParentId());
                    if (type.equals(parent.getType())) {
                        return parent;
                    } else {
                        return findParentByType(parent, type);
                    }
                } catch (LogicException e) {
                    return null;
                }
            }
        }
    }

    /**
     * 根据列表获取上级是项目管理组织的清单
     *
     * @param hrOrganizationVos
     * @return
     */
    private List<HrOrganizationVo> queryAllProjectManagementOrganizations(List<HrOrganizationVo> hrOrganizationVos) {
        return hrOrganizationVos.stream().map(hrOrganizationVo -> findParentByType(hrOrganizationVo, HrOrganizationTypeEnum.PROJECT_MANAGEMENT_ORGANIZATION.getValue()))
                .filter(hrOrganizationVo -> hrOrganizationVo != null).collect(Collectors.toList());
    }


    @Override
    public List<HrOrganizationVo> queryAllHROrganizationListByType(boolean isCompany, boolean isCompanyLeader, boolean isCompanyManagementOrganization, boolean isProjectManagementOrganization, boolean isSubordinateOrganization) {
        List<String> typeList = new ArrayList<>();

        if (isCompany) {
            typeList.add(HrOrganizationTypeEnum.COMPANY.getValue());
        }

        if (isCompanyLeader) {
            typeList.add(HrOrganizationTypeEnum.COMPANY_LEADER.getValue());
        }

        if (isCompanyManagementOrganization) {
            typeList.add(HrOrganizationTypeEnum.COMPANY_MANAGEMENT_ORGANIZATION.getValue());
        }

        if (isProjectManagementOrganization) {
            typeList.add(HrOrganizationTypeEnum.PROJECT_MANAGEMENT_ORGANIZATION.getValue());
        }

        if (isSubordinateOrganization) {
            typeList.add(HrOrganizationTypeEnum.SUBORDINATE_ORGANIZATION.getValue());
        }

        return domainTransformToView(hrOrganizationRepository.selectHrOrganizationByTypeList(typeList));
    }

    @Override
    public HrOrganizationVo queryAllTopScopeHrOrganizations(List<Long> hrOrganizationIds, boolean showAll) {
        List<String> typeList = new ArrayList<>();
        List<String> nodeTypeList = new ArrayList<>();

        List<HrOrganizationVo> allHrOrganizationList = this.getAllHrOrganizationList();
        nodeTypeList.add(HrOrganizationTypeEnum.PROJECT_MANAGEMENT_ORGANIZATION.getValue());
        nodeTypeList.add(HrOrganizationTypeEnum.COMPANY.getValue());
        // 获取根节点
        HrOrganizationVo root = hrOrganizationToVo(hrOrganizationRepository.selectHrOrganizationRoot());

        // 判断是否显示全部
        if (!showAll) {
            // 获取用户所在分配的企业组织
            List<HrOrganizationVo> assignmentHrOrganizations = hrOrganizationIds.stream().map(hrOrganizationId -> {
                try {
                    return this.getHrOrganizationViewWithTypeList(hrOrganizationId, nodeTypeList);
                } catch (Exception e) {
                    return null;
                }
            }).filter(Objects::nonNull).collect(Collectors.toList());

            // 公司管理组织、公司领导层级组织
            Optional<HrOrganizationVo> optional = assignmentHrOrganizations.stream().filter(hrOrganization ->
                    new ArrayList<String>() {{
                        add(HrOrganizationTypeEnum.COMPANY_MANAGEMENT_ORGANIZATION.getValue());
                        add(HrOrganizationTypeEnum.COMPANY_LEADER.getValue());
                    }}.contains(hrOrganization.getType())
            ).findFirst();

            // 如果当前人员没有公司管理组织、公司领导层级的分配，则抓取所有涉及分配的项目管理组织
            if (!optional.isPresent()) {
                HrOrganizationVo hrOrganizationVo = root.setHrOrganizationChildren(queryAllProjectManagementOrganizations(assignmentHrOrganizations));
                return filterHrOrganizationVoByNodeList(hrOrganizationVo, nodeTypeList);
            }
        }

        typeList.add(HrOrganizationTypeEnum.PROJECT_MANAGEMENT_ORGANIZATION.getValue());
        // 管理员或者符合条件的则返回全部管理部门
        return root.setHrOrganizationChildren(dozerUtil.convertor(hrOrganizationRepository.selectHrOrganizationByTypeList(typeList), HrOrganizationVo.class));
    }

    @Override
    public List<Long> getParentHrOrganizationIdsByHrOrganizationId(Long hrOrganizationId) {
        HrOrganization hrOrganization = hrOrganizationRepository.selectByHrOrganizationId(hrOrganizationId);
        List<Long> hrOrganizationIds = new ArrayList<>();

        if (hrOrganization != null) {
            if (hrOrganization.getParentId() != null) {
                hrOrganizationIds.add(hrOrganization.getParentId());
                hrOrganizationIds.addAll(getParentHrOrganizationIdsByHrOrganizationId(hrOrganization.getParentId()));
            }
        }

        return hrOrganizationIds;
    }

    @Override
    public List<Long> getAllHrOrganizationIdsWhenYouAreInCompanyLevel(List<Long> internalAssignmentHrOrganizationIds) {
        AuthorityAccessResponse accessResponse = authorityUtil.getLoginAccess();
        if (accessResponse.isAdmin()) {
            return hrOrganizationRepository.selectAll().stream().map(HrOrganization::getHrOrganizationId).collect(Collectors.toList());
        }

        // 可以查看所有组织的组织类型
        List<String> types = new ArrayList<String>() {{
            add(HrOrganizationTypeEnum.COMPANY.getValue());
            add(HrOrganizationTypeEnum.COMPANY_LEADER.getValue());
            add(HrOrganizationTypeEnum.COMPANY_MANAGEMENT_ORGANIZATION.getValue());
        }};

        Optional<Long> optional = internalAssignmentHrOrganizationIds.stream().filter(hrOrganizationId -> {
            HrOrganization basic = hrOrganizationRepository.selectByHrOrganizationId(hrOrganizationId);
            if (basic != null) {
                return (types.contains(basic.getType()));
            } else {
                return false;
            }
        }).findAny();

        if (optional.isPresent()) {
            return hrOrganizationRepository.selectAll().stream().map(HrOrganization::getHrOrganizationId).collect(Collectors.toList());
        } else {
            return new ArrayList<>();
        }
    }

    @Override
    public Organization getOrganizationOne(OrganizationOneQueryCommand organizationOneQueryCommand) {
        OrganizationQuery organizationQuery = appConverter.organizationOneQueryCommandToOrganizationQuery(organizationOneQueryCommand);
        return hrOrganizationRepository.getOrganizationOne(organizationQuery);
    }

    @Override
    public List<Organization> getOrganizationList(OrganizationListQueryCommand organizationListQueryCommand) {
        OrganizationQuery organizationQuery = appConverter.organizationListQueryCommandToOrganizationQuery(organizationListQueryCommand);
        return hrOrganizationRepository.getOrganizationList(organizationQuery);
    }

    @Override
    public List<Organization> getOrganizationListWithoutToken(OrganizationListQueryCommand organizationListQuerycommand) {
        OrganizationQuery organizationQuery = appConverter.organizationListQueryCommandToOrganizationQuery(organizationListQuerycommand);
        return hrOrganizationRepository.getOrganizationListWithoutToken(organizationQuery);
    }


    private HrOrganizationVo filterHrOrganizationVoByNodeList(HrOrganizationVo hrOrganizationVo, List<String> nodeTypeList) {
        List<HrOrganizationVo> hrOrganizationChildren = hrOrganizationVo.getHrOrganizationChildren();

        if (null != hrOrganizationChildren) {
            Iterator<HrOrganizationVo> iterator = hrOrganizationChildren.listIterator();
            while (iterator.hasNext()) {
                HrOrganizationVo hrOrganizationVoTemp = iterator.next();
                if (nodeTypeList.contains(hrOrganizationVoTemp.getType())) {
                    filterHrOrganizationVoByNodeList(hrOrganizationVoTemp, nodeTypeList);
                } else {
                    iterator.remove();
                }
            }
        }

        return hrOrganizationVo;
    }

    @Override
    public List<AllOrganizationVo> getAllOrganizationVos(List<Long> ids) {
        List<DingOrg> list = hrOrganizationRepository.getAllDingOrgList(ids);
        return dozerUtil.convertor(list, AllOrganizationVo.class);
    }
}
